import modules from "./modules";
import proj4 from "proj4";
import { getRatio } from "../utils/common.js";
import transform from "../utils/transform.js";
import gcj02Proj from "./lib/gcj02Proj.js";
import { io } from "jsts";
import WKT from "wkt";
import * as turf from "@turf/turf";
import { WindLayer } from 'ol-wind';

class MapClass {
  constructor(el, options) {
    this.el = el;
    this.options = options;
    this.modules = modules;
    
    // jsts工具、缓冲区、拓扑计算
    this.jstsParser = new io.OL3Parser();
    this.jstsParser.inject(
      this.modules.Point,
      this.modules.LineString,
      this.modules.LinearRing,
      this.modules.Polygon,
      this.modules.MultiPoint,
      this.modules.MultiLineString,
      this.modules.MultiPolygon,
      this.modules.GeometryCollection
    );
    
    this.init();
  }
  async init() {
    // 创建地图
    this.viewProjection = this.setProjection(this.options.mapOptions.sr);
    this.map = new this.modules.Map({
      target: this.el,
      layers: [...this.initBaseLayers(this.options.baseLayers)],
      view: new this.modules.View({
        center: [this.options.mapOptions.centerX, this.options.mapOptions.centerY],
        zoom: this.options.mapOptions.zoom || 12,
        minZoom: this.options.mapOptions.minZoom || 4,
        maxZoom: this.options.mapOptions.maxZoom || 18,
        projection: this.viewProjection,
        extent: this.options.mapOptions.mapExtent || this.viewProjection.getExtent(),
        constrainResolution: true, //控制缩放时级别为zoom整数级别
      }),
      controls: this.modules.defaultControls({
        attribution: false,
        rotate: false,
        zoom: false
      })
    });
    // 监听地图dom变化，更新地图
    const Observer = new ResizeObserver(() => {
      this.map && this.map.updateSize();
    });
    Observer.observe(this.el);
    // 添加比例尺
    this.map.addControl(new this.modules.ScaleLine());
    // 绘制图层
    this.drawLayerSource = new this.modules.VectorSource({wrapX: false});
    this.drawLayer = new this.modules.VectorLayer({
      zIndex: 99,
      source: this.drawLayerSource
    });
    this.map.addLayer(this.drawLayer);
    // 高亮显示图层
    this.highLightLayerSource = new this.modules.VectorSource({wrapX: false});
    let highLightLayer = new this.modules.VectorLayer({
      zIndex: 98,
      source: this.highLightLayerSource
    });
    this.map.addLayer(highLightLayer);
    // 弹窗
    this.overlay = new this.modules.Overlay({});
    this.map.addOverlay(this.overlay);    
  }
  // 设置坐标系
  setProjection(sr) {
    let viewProjection;
    if(sr.isEpsg) {
      if(sr.id == 3857 || sr.id == 4326) {
        viewProjection = this.modules.getProjection('EPSG:' + sr.id);
      }else {
        // 注册proj4坐标系
        let srParams = sr.params || transform.getEpsgParams("EPSG:"+ sr.id);
        proj4.defs("EPSG:"+ sr.id, srParams);
        this.modules.register(proj4);
        viewProjection = this.modules.getProjection('EPSG:' + sr.id);
        let extent = viewProjection.getUnits() === "m" ? [-2.0037508342787E7, -2.0037508342787E7,2.0037508342787E7, 2.0037508342787E7] : [-180, -90, 180, 90];
        viewProjection.setExtent(extent);
      }
    }else {
      viewProjection = this.modules.getProjection('EPSG:3857');
    }
    return viewProjection;
  }
  // 地图加载完成
  mapLoaded() {
    return new Promise(resolve => {
      this.map.on("rendercomplete", evt => {
        resolve(true);
      });
    });
  }
  // 初始化底图
  initBaseLayers(layers) {
    if(!layers || !layers.length) return [];
    return layers.map(item => {
      return this.createBaseLayer(item, false);
    });
  }
  /**
   * 创建图层
   * @param {*} options 图层配置对象
   * @param {*} isAdd 是否添加到地图
   */
  createBaseLayer(options, isAdd = true) {
    let visible = options.visible === undefined ? true : Boolean(options.visible);
    let newLayer;
    if(options.layerType === "XYZ") {
      newLayer = new this.modules.TileLayer({
        source: this.createSource(options.layerType, options),
        id: options.id,
        visible: visible
      });
    }else if(options.layerType === "Arcgis") {
      newLayer = new this.modules.TileLayer({
        source: this.createSource(options.layerType, options),
        id: options.id,
        visible: visible
      });
    }else if(options.layerType === "WMTS") {
      let resolutions = [], matrixIds = [];
      for (let z = options.level.min; z <= Number(options.level.max); ++z) {
        resolutions[z] = options.maxResolution / Math.pow(2, z);
        matrixIds[z] = options.preMatrixId ? options.preMatrixId + z : z;
      }
      newLayer = new this.modules.TileLayer({
        source: this.createSource(options.layerType, options),
        id: options.id,
        visible: visible
      });
    }else if(options.layerType === "GCJ02") {
      let gcj02Extent = [-20037508.342789244, -20037508.342789244, 20037508.342789244, 20037508.342789244];
      let gcjMecator = new this.modules.Projection({
        code: "GCJ-02",
        extent: gcj02Extent,
        units: "m"
      });
      this.modules.addProjection(gcjMecator);
      this.modules.addCoordinateTransforms("EPSG:4326", gcjMecator, gcj02Proj.ll2gmerc, gcj02Proj.gmerc2ll);
      this.modules.addCoordinateTransforms("EPSG:3857", gcjMecator, gcj02Proj.smerc2gmerc, gcj02Proj.gmerc2smerc);
      options.projection = gcjMecator; //设置自定义投影
      newLayer = new this.modules.TileLayer({
        source: this.createSource("XYZ", options),
        id: options.id,
        visible: visible
      });
    }else if(options.layerType === "GeoJSON") {
      newLayer = new this.modules.VectorLayer({
        id: options.id,
        source: new this.modules.VectorSource({
          projection: this.viewProjection,
          url: options.url, //GeoJSON的文件路径
          format: new this.modules.formatGeoJSON(),
          wrapX: false
        }),
        style: options.style,
        visible: visible,
        ...(options.extra || {})
      });
    }
    // 直接添加到地图
    if(isAdd && this.map) {
      this.map.addLayer(newLayer);
    }
    return newLayer;
  }
  /**
   * 创建风场图层
   * @param {*} data 风场数据，json
   * @param {*} options 配置windOptions https://blog.sakitam.com/wind-layer/guide/index
   * @param {Boolean} isAdd 是否添加到地图
   * @returns 
   */
  createWindLayer(data, options = {}, isAdd = true) {
    let windOptions = {
      paths: 1000, //风场粒子数量
      colorScale: [ //风场颜色
        // "rgb(36,104, 180)",
        // "rgb(60,157, 194)",
        // "rgb(128,205,193 )",
        // "rgb(151,218,168 )",
        // "rgb(198,231,181)",
        // "rgb(238,247,217)",
        // "rgb(255,238,159)",
        // "rgb(252,217,125)",
        // "rgb(255,182,100)",
        // "rgb(252,150,75)",
        // "rgb(250,112,52)",
        // "rgb(245,64,32)",
        // "rgb(237,45,28)",
        // "rgb(220,24,32)",
        // "rgb(180,0,35)",

        "rgb(0, 255, 0)",
        "rgb(174, 200, 0)",
        "rgb(255, 255, 0)",
        "rgb(250, 195, 27)",
        "rgb(245, 64, 32)",
      ],
      lineWidth: 2, //风场粒子线宽
      ...options
    };
    // 控制风场速度和长度
    windOptions.velocityScale = this.map.getView().getResolution();
    const windLayer = new WindLayer(data, {
      forceRender: false,
      windOptions,
    });
    // 将地图缩放事件添加到图层，便于移除图层时，移除事件监听
    windLayer.viewScaleEvent = this.viewScaleListener(evt => {
      windOptions.velocityScale = evt.target.getResolution();
      windLayer.setWindOptions(windOptions);
    });
    if(isAdd) this.map.addLayer(windLayer);
    return windLayer;
  }
  /**
   * 创建数据源
   * @param {*} type 数据源类型
   * @param {*} options 图层配置
   * @returns 
   */
  createSource(type, options) {
    const tileLoadFunction = options.filter && function (imageTile, src) {
      let img = new Image();
      img.setAttribute('crossOrigin', 'anonymous');
      img.src = src;
      img.onload = function () {
        let canvas = document.createElement('canvas');
        let w = img.width;
        let h = img.height;
        canvas.width = w;
        canvas.height = h;
        let context = canvas.getContext('2d');
        context.filter = options.filter === 'default' ? 'grayscale(98%) invert(100%) sepia(20%) hue-rotate(180deg) saturate(1600%) brightness(80%) contrast(90%)' : options.filter;
        context.drawImage(img, 0, 0, w, h, 0, 0, w, h);
        imageTile.getImage().src = canvas.toDataURL('image/png');
      }
    }
    if(type === "XYZ") {
      return new this.modules.XYZSource({ 
        crossOrigin: "anonymous",
        projection: options.projection,//设置自定义投影
        url: options.url,
        wrapX: false,
        maxZoom: options.maxZoom, //设置瓦片最大级别，放大后模糊
        tileLoadFunction
      });
    }else if(type === "Arcgis") {
      return new this.modules.TileArcGISRest({ 
        crossOrigin: "anonymous",
        url: options.url,
        wrapX: false,
        tileLoadFunction
      });
    }else if(type === "WMTS") {
      let resolutions = [], matrixIds = [];
      for (let z = options.level.min; z <= Number(options.level.max); ++z) {
        resolutions[z] = options.maxResolution / Math.pow(2, z);
        matrixIds[z] = options.preMatrixId ? options.preMatrixId + z : z;
      }
      return new this.modules.WMTSSource({
        crossOrigin: "anonymous", 
        url: options.url,
        layer: options.layer,
        matrixSet: options.matrixSet,
        format: "image/png",
        style: 'default',
        tileGrid: new this.modules.WMTSTileGrid({
          origin: this.viewProjection.getUnits() === "m" ? [-2.0037508342787E7, 2.0037508342787E7] : [-180, 90],
          resolutions: resolutions,
          matrixIds: matrixIds,
        }),
        wrapX: false,
        tileLoadFunction
      });
    }else if(type === "GeoJSON") {
      return new this.modules.VectorSource({
        projection: this.viewProjection,
        url: options.url, //GeoJSON的文件路径
        format: new this.modules.formatGeoJSON(),
        wrapX: false
      });
    }
  }
  /**
   * 设置图层显示隐藏
   * @param {String|Array} layerId 图层id
   * @param {Boolean} visible 是否显示
   */
  setLayerVisible(layerId, visible) {
    let isArray = Array.isArray(layerId);
    this.map.getLayers().forEach(item => {
      if(isArray) {
        if(layerId.includes(item.getProperties().id)) {
          item.setVisible(visible);
        }
      }else {
        if(layerId === item.getProperties().id) {
          item.setVisible(visible);
        }
      }
    });
  }
  /**
   * 开启卷帘
   * @param {*} swipeLayers [{
   *  layer 卷帘图层
   *  side "left/right" 图层的两侧
   * }, {}, ...]
   */
  startSwipe(swipeLayers, swipeDom) {
    let map = this.map;
    if(!swipeDom) {
      // 获取当前地图容器下的swipe dom，防止多地图情况下，获取swipe dom问题
      this.el.childNodes.forEach(item => {
        if(item.className === "swipe-container") {
          swipeDom = item;
        }
      });
    }
    swipeDom.style.display = "block";
    this.swipeDom = swipeDom;
    let diffX;
    swipeDom.onmousedown = function(event) {
      let e = event || window.event; 
      // 鼠标点击元素那一刻相对于元素左侧边框的距离=点击时的位置相对于浏览器最左边的距离-物体左边框相对于浏览器最左边的距离
      diffX = e.clientX - this.offsetLeft;
      document.onmousemove = function(event) {
        let e = event || window.event;
        let moveX = e.clientX - diffX;
        if (moveX < 0) {
          moveX = 0
        } else if (moveX > window.innerWidth - swipeDom.offsetWidth / 2) {
          moveX = window.innerWidth - swipeDom.offsetWidth / 2
        }
        swipeDom.style.left = moveX + 'px';
        
        //重新渲染图层
        map.render();
      };
      document.onmouseup = function() {
        this.onmousemove = null;
        this.onmouseup = null;
      }
    };

    function onPrerender(layer, side) {
      let swipeListener = layer.on('prerender', event => {
        /**
         * 获取当前浏览器窗口的缩放比例
         * window.devicePixelRatio
         * 注：宽或高乘以devicePixelRatio, 否则地图渲染无法填充真是高度 
         */
        let devicePixelRatio = getRatio();
        let mapWidth = map.getSize()[0] * devicePixelRatio;
        let mapHeight = map.getSize()[1] * devicePixelRatio;
        let width = swipeDom.offsetLeft * devicePixelRatio;
        let startWidth, endWidth;
        if(side === "left") {
          startWidth = 0;
          endWidth = width;
        }
        if(side === "right") {
          startWidth = width;
          endWidth = mapWidth - width;
        }
        let ctx = event.context;
        ctx.save();
        ctx.beginPath();
        ctx.rect(startWidth, 0, endWidth, mapHeight);
        ctx.clip();//裁剪
      });
      layer.on('postrender', function (event) {
        const ctx = event.context;
        ctx.restore();
      });
      return swipeListener;
    }

    // 绑定图层卷帘事件
    this.swipeListeners = swipeLayers.map(item => {
      return onPrerender(item.layer, item.side);
    });
    //重新渲染图层
    map.render();
  }
  // 关闭卷帘
  closeSwipe() {
    this.swipeDom.style.display = "none";
    // 事件解绑
    this.swipeListeners.forEach(item => {
      if(item) this.modules.unByKey(item);
    });
    //重新渲染图层
    this.map.render();
  }
  /**
   * 屏幕截图
   * @param {*} options {
   *   extent 范围坐标
   *   padding 截图边距
   *   callback 回调函数，返回截图数据
   * }
   */
  takeScreenShot(options) {
    this.map.once('rendercomplete', () => {
      let width, height, startX, startY;
      let padding = options.padding || 0;
      // 截取要素范围屏幕
      if(options.extent) {
        let extent = options.extent;
        //地理坐标转换屏幕坐标 
        let LTcoord = [extent[0], extent[3]];
        let leftTopPosition = this.map.getPixelFromCoordinate(LTcoord);
        let BRcoord = [extent[2], extent[1]];
        let bottomRightPosition = this.map.getPixelFromCoordinate(BRcoord);
        //计算宽度以及高度像素
        width = Math.abs(bottomRightPosition[0] - leftTopPosition[0]) + padding * 2;
        height = Math.abs(bottomRightPosition[1] - leftTopPosition[1]) + padding * 2;
        //计算左上角屏幕坐标
        startX = leftTopPosition[0] - padding;
        startY = leftTopPosition[1] - padding;
      }
      // 截取地图全部屏幕
      else {
        let viewPort = this.map.getViewport();
        width = viewPort.clientWidth;
        height = viewPort.clientHeight;
        startX = 0;
        startY = 0;
      }
      const mapCanvas = document.createElement('canvas');
      mapCanvas.width = width;
      mapCanvas.height = height;
      const mapContext = mapCanvas.getContext('2d');
      document.querySelectorAll('.ol-layer canvas').forEach(canvas => {
        if (canvas.width > 0) {
          const opacity = canvas.parentNode.style.opacity;
          mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity);
          const transform = canvas.style.transform;
          const matrix = transform.match(/^matrix\(([^(]*)\)$/)[1].split(',').map(Number);
          CanvasRenderingContext2D.prototype.setTransform.apply(mapContext, matrix);
          mapContext.drawImage(canvas, -startX, -startY);
        }
      });
      if(options.callback) {
        options.callback(mapCanvas.toDataURL());
      }
    });
    this.map.renderSync();
  }
  /**
   * 绘制图形
   * @param {String} type 绘制类型 ["Point","LineString","Polygon","Circle","Rectangle"]
   * @param {Function} callback 返回绘制feature
   * @param {Boolean} isAgain 是否连续绘制
   */
  startDraw(type, callback, isAgain) {
    this.closeDraw(); //先关闭绘制
    this.drawTools = new this.modules.Draw({
      source: this.drawLayerSource,
      type: type === "Rectangle" ? "Circle" : type, //绘制矩形需要type="Circle"
      geometryFunction: type === "Rectangle" ? this.modules.createBox() : undefined, //绘制矩形函数
    });
    this.map.addInteraction(this.drawTools);
    this.drawTools.on("drawend", evt => {
      if(!isAgain) {
        // 防止触发双击放大事件
        setTimeout(() => this.map.removeInteraction(this.drawTools));
      }
      if(callback) callback(evt.feature);
    });
  }
  // 关闭绘制工具
  closeDraw() {
    if(this.drawTools) this.map.removeInteraction(this.drawTools);
  }
  // 清除绘制数据
  clearDraw() {
    this.closeDraw();
    this.drawLayerSource.clear();
  }
  // 开启编辑
  startModify(editFeature, callback) {
    let isMultiEdit = Array.isArray(editFeature);
    let featureCollection = new this.modules.Collection(isMultiEdit ? editFeature : [editFeature]);
    this.modifyTool = new this.modules.Modify({
      features: featureCollection
    });
    this.map.addInteraction(this.modifyTool);
    this.modifyTool.on("modifyend", evt => {
      if(callback) callback(isMultiEdit ? evt.features : evt.features.getArray()[0]);
    });
    this.snapTool = new this.modules.Snap({
      features: featureCollection
    });
    this.map.addInteraction(this.snapTool);
  }
  // 关闭编辑
  closeModify() {
    if(this.modifyTool) this.map.removeInteraction(this.modifyTool);
    if(this.snapTool) this.map.removeInteraction(this.snapTool);
  }
  // 测量长度
  measureLegth() {
    this.closeDraw();
    this.drawTools = new this.modules.Draw({
      source: this.drawLayerSource,
      type: "LineString",
    });
    this.map.addInteraction(this.drawTools);
    this.drawTools.on("drawend", evt => {
      // 防止触发双击放大事件
      setTimeout(() => this.map.removeInteraction(this.drawTools));
      evt.feature.setStyle(new this.modules.Style({
        stroke: new this.modules.Stroke({
          color: "#3F97FD",
          width: 2,
        }),
      }));
      let geometry = evt.feature.getGeometry();
      let length = this.modules.getLength(geometry, {
        projection: this.viewProjection
      });
      let endPoint = geometry.getLastCoordinate();
      let feature = new this.modules.Feature({
        geometry: new this.modules.Point(endPoint)
      });
      feature.setStyle(new this.modules.Style({
        text: new this.modules.Text({
          text: "长度: " + length.toFixed(3) + "m",
          fill: new this.modules.Fill({
            color: "#ff0000"
          }),
          scale: 2,
          offsetY: -10
        })
      }));
      this.drawLayerSource.addFeature(feature);
    });
  }
  // 测量面积
  measureArea() {
    this.closeDraw();
    this.drawTools = new this.modules.Draw({
      source: this.drawLayerSource,
      type: "Polygon",
    });
    this.map.addInteraction(this.drawTools);
    this.drawTools.on("drawend", evt => {
      // 防止触发双击放大事件
      setTimeout(() => this.map.removeInteraction(this.drawTools));
      evt.feature.setStyle(new this.modules.Style({
        fill: new this.modules.Fill({
          color: "rgba(255, 255, 255, 0.3)"
        }),
        stroke: new this.modules.Stroke({
          color: "#3F97FD",
          width: 2,
        }),
      }));
      let geometry = evt.feature.getGeometry();
      let area = this.modules.getArea(geometry, {
        projection: this.viewProjection
      });
      let center = this.modules.getExtentCenter(geometry.getExtent());
      let feature = new this.modules.Feature({
        geometry: new this.modules.Point(center)
      });
      feature.setStyle(new this.modules.Style({
        text: new this.modules.Text({
          text: "面积: " + area.toFixed(3) + "m²",
          fill: new this.modules.Fill({
            color: "#ff0000"
          }),
          scale: 2
        })
      }));
      this.drawLayerSource.addFeature(feature);
    });
  }
  // 地图放大
  zoomIn() {
    this.map.getView().setZoom(this.map.getView().getZoom() + 1);
  }
  // 地图缩小
  zoomOut() {
    this.map.getView().setZoom(this.map.getView().getZoom() - 1);
  }
  // 获取当前缩放级别
  getCurZoom() {
    return this.map.getView().getZoom();
  }
  // 获取当前视图范围
  getCurViewExtent() {
    return this.modules.fromExtent(this.map.getView().calculateExtent());
  }
  // 获取坐标值
  getCoordinates(geometry) {
    return geometry.getCoordinates();
  }
  // 获取图形的中心点
  getGeometryCenter(geometry) {
    let center;
    if(geometry.getType() === "Point") {
      return geometry;
    }else {
      center = this.modules.getExtentCenter(geometry.getExtent());
    }
    return this.createPoint(center[0], center[1]);
  }
  // 获取面的重心
  getPolygonCentroid(polygon) {
    if(!polygon) return;
    let positions = polygon.getCoordinates();
    try {
      let polygon = turf.polygon(positions);
      let centroid = turf.centroid(polygon);
      return centroid.geometry.coordinates;
    } catch (err) {
      console.log('log--- err', err);
      return;
    }
  }
  // 获取图形类型
  getGeometryType(geometry) {
    return geometry.getType();
  }
  /**
   * 坐标缩放定位
   * @param {Number} x x坐标值
   * @param {Number} y y坐标值
   * @param {Number} zoom 缩放级别（可选）
   */
  setCenterZoom(x, y, zoom) {
    this.map.getView().setCenter([x, y]);
    zoom && this.map.getView().setZoom(zoom);
  }
  /**
   * 坐标缩放定位（动画）
   * @param {Number} x x坐标值
   * @param {Number} y y坐标值
   * @param {Number} zoom 缩放级别
   */
  animateTo(x, y, zoom) {
    let option = {
      center: [x, y]
    };
    zoom && (option.zoom = zoom);
    this.map.getView().animate(option);
  }
  /**
   * 要素定位
   * @param {Object<Geometry>||Array<Geometry>} geometry 单个或多个图形要素
   * @param {Function} callback 定位结束回调 （可选）
   */
  zoomToGeometry(geometry, callback) {
    if(Array.isArray(geometry)) {
      geometry = this.getUnionGeometry(geometry);
    }
    let padding = this.map.getViewport().clientWidth / 10;
    this.map.getView().fit(geometry, {
      size: this.map.getSize(),
      padding: [padding, padding, padding, padding],
      duration: 500,
      callback
    });
  }
  /**
   * 点坐标转屏幕坐标
   * @param {Object<Geometry>} point 点要素
   * @returns {Object} {x: 123, y: 456}
   */
  pointToScreen(point) {
    return this.map.getPixelFromCoordinate(point.getCoordinates());
  }
  // 要素数据转geojson
  geometryToGeojson(geometry) {
    return new this.modules.formatGeoJSON().writeGeometryObject(geometry);
  }
  // geojson转要素数据
  geojsonToGeometry(geojson) {
    return new this.modules.formatGeoJSON().readGeometry(geojson);
  }
  // 要素数据转wkt
  geometryToWkt(geometry) {
    let geojson = new this.modules.formatGeoJSON().writeGeometryObject(geometry);
    return WKT.stringify(geojson);
  }
  // wkt转要素数据
  wktToGeometry(wkt) {
    let geojson = WKT.parse(wkt);
    return new this.modules.formatGeoJSON().readGeometry(geojson);
  }
  // 图形要素转json
  featureToJson(feature) {
    let geojson = new this.modules.formatGeoJSON().writeFeatureObject(feature);
    return JSON.stringify(geojson);
  }
  // json<Feature>转要素数据
  jsonToFeature(json) {
    if(!json) return;
    return new this.modules.formatGeoJSON().readFeature(json);
  }
  // json<FeatureCollection> 转要素集合数据
  jsonToFeatures(json) {
    if(!json) return [];
    return new this.modules.formatGeoJSON().readFeatures(json);
  }
  /**
   * 创建点图形
   * @param {Number} x x坐标值
   * @param {Number} y y坐标值
   * @returns Object<Point> 点图形数据
   */
  createPoint(x, y) {
    return new this.modules.Point([x, y]);
  }
  /**
   * 创建线图形
   * @param {Number} coordinates 坐标值[[x, y], [x, y]]
   * @returns Object<Polyline> 线图形数据
   */
  createPolyline(coordinates) {
    return new this.modules.LineString(coordinates);
  }
  /**
   * 创建面图形
   * @param {Number} coordinates 坐标值[[[x, y], [x, y]]]
   * @returns Object<Polygon> 面图形数据
   */
  createPolygon(coordinates) {
    return new this.modules.Polygon(coordinates);
  }
  /**
   * 构建缓冲区
   * @param {Object} geometry 空间数据
   * @param {Number} radius 缓冲半径
   * @returns Object<Geometry> 缓冲区图形 
   */
  createBuffer(geometry, radius) {
    // 获取每单位数据等于多少米，如：1° = 111319.49079327358m
    let meters = this.viewProjection.getMetersPerUnit();
    let buffered = this.jstsParser.read(geometry).buffer(radius / meters);
    return this.jstsParser.write(buffered);
  }
  /**
   * 添加
   * @param {*} options {
   *  el DOM元素
   *  position 坐标位置[x, y]
   *  offset 位置偏移[1, 2]（可选）
   *  positioning 放置方式（可选）
   * }
   */
  createOverlay(options) {
    let overlay = new this.modules.Overlay({
      element: options.el,
      position: options.position,
      offset: options.offset || [0, 0],
      positioning: options.positioning || 'center-center',
      stopEvent: false
    });
    this.map.addOverlay(overlay);
    return overlay;
  }
  /**
   * 获取圆点样式
   * @param options {
   *  color 填充颜色#ff0000 | [r, g, b, a]
   *  size 圆点大小，像素数值值大小
   *  outLineColor 边线颜色（可选）
   *  outLineWidth 边线宽度（可选）
   * }
   * @returns Object 样式对象
   */ 
  getPointStyle(options) {
    return new this.modules.Style({
      image: new this.modules.CircleStyle({
        radius: options.size / 2,
        fill: new this.modules.Fill({
          color: options.color
        }),
        stroke: new this.modules.Stroke({
          color: options.outLineColor || '#fff',
          width: options.outLineWidth || 1
        })
      }),
      zIndex: 3
    });
  }
  /**
   * 获取点图标样式
   * @param options {
   *  url 图标地址
   *  scale 图标缩放比例
   *  xoffset x偏移 （可选）
   *  yoffset y偏移 （可选）
   * }
   * @returns Object 样式对象
   */  
  getMarkerStyle(options) {
    return new this.modules.Style({
      image: new this.modules.Icon({
        src: options.url,
        scale: options.scale || 1,
        anchor: [options.xoffset || 0.5, options.yoffset || 1],
      }),
      zIndex: 4
    });
  }
  /**
   * 获取标注样式
   * @param options {
   *  text 文本内容
   *  color 填充颜色#ff0000 | [r, g, b, a]
   *  fontSize 字体大小
   *  outLineColor 边线颜色
   *  outLineWidth 边线宽度
   *  xoffset x偏移 （可选）
   *  yoffset y偏移 （可选）
   * }
   * @returns Object 样式对象
   */ 
  getTextStyle(options) {
    return new this.modules.Style({
      text: new this.modules.Text({
        font: options.font || undefined,
        text: String(options.text) || "",
        fill: new this.modules.Fill({
          color: options.color || '#fff',
        }),
        stroke: options.outLineWidth && new this.modules.Stroke({
          color: options.outLineColor || "#000",
          width: options.outLineWidth
        }),
        scale: options.fontSize ? options.fontSize / 12 : 1,
        offsetX: options.xoffset || 0,
        offsetY: options.yoffset || 0,
      }),
      zIndex: 5
    });
  }
  /**
   * 获取带标注图标样式
   * @param options {
   *  url 图标地址
   *  scale 图标缩放比例
   *  xoffset x偏移 （可选）
   *  yoffset y偏移 （可选）
   *  text 文本内容
   *  color 填充颜色#ff0000 | [r, g, b, a]
   *  fontSize 字体大小
   *  outLineColor 边线颜色
   *  outLineWidth 边线宽度
   *  txoffset x偏移 （可选）
   *  tyoffset y偏移 （可选）
   * }
   * @returns Object 样式对象
   */ 
  getMarkerTextStyle(options) {
    return new this.modules.Style({
      image: new this.modules.Icon({
        src: options.url,
        scale: options.scale,
        anchor: [options.xoffset || 0.5, options.yoffset || 1],
      }),
      text: new this.modules.Text({
        text: String(options.text),
        fill: new this.modules.Fill({
          color: options.color,
        }),
        stroke: options.outLineWidth && new this.modules.Stroke({
          color: options.outLineColor || "#000",
          width: options.outLineWidth
        }),
        scale: options.fontSize / 12,
        offsetX: options.txoffset || 0,
        offsetY: options.tyoffset || 0,
      }),
      zIndex: 9
    });
  }
  /**
   * 获取线样式
   * @param options {
   *  color 填充颜色#ff0000 | [r, g, b, a]
   *  width 线宽度 1
   *  style 线样式 solid-实线 dash-虚线 （可选）
   * }
   * @returns Object 样式对象
   */ 
  getLineStyle(options) {
    return new this.modules.Style({
      stroke: new this.modules.Stroke({
        lineJoin: "round",
        color: options.color,
        width: options.width,
        lineDash: options.style === "dash" ? [10, 10] : null,
      }),
      zIndex: 2
    });
  }
  /**
   * 获取面样式
   * @param options {
   *  color 填充颜色#ff0000 | [r, g, b, a]
   *  outLineColor 边线颜色#ff0000 | [r, g, b, a]
   *  outLineWidth 边线宽度 1,  为0时，不加边线
   *  outLineStyle 边线样式 solid-实线 dash-虚线 （可选）
   * }
   * @returns Object 样式对象
   */
  getPolygonStyle(options) {
    return new this.modules.Style({
      fill: new this.modules.Fill({
        color: options.color,
      }),
      stroke: options.outLineWidth && new this.modules.Stroke({
        color: options.outLineColor,
        width: options.outLineWidth,
        lineDash: options.outLineStyle === "dash" ? [10, 10] : null,
      }),
      zIndex: 1
    });
  }
  /**
   * 创建填充样式
   * @param {*} color 填充颜色#ff0000 | [r, g, b, a]
   */
  getFillStyle(color) {
    return new this.modules.Fill({ color });
  }
  /**
   * 创建线样式
   * @param {*} options {
   *  color 填充颜色#ff0000 | [r, g, b, a]
   *  width 线宽度 1
   *  style 线样式 solid-实线 dash-虚线 （可选）
   *  extra 其他参数（可选）
   * }
   */
  getStrokeStyle(options) {
    return new this.modules.Stroke({
      color: options.color,
      width: options.width,
      lineDash: options.style === "dash" ? [10, 10] : null,
      ...(options.extra || {})
    });
  }
  /**
   * 获取合并样式，支持多样式共存（如：点 + 标注）
   * @param options {
   *  outline: {
   *    color 填充颜色#ff0000 | [r, g, b, a]
   *    width 线宽度 1
   *    style 线样式 solid-实线 dash-虚线 （可选）
   *    extra 其他参数（可选）
   *  },
   *  fill: {
   *    color 填充颜色#ff0000 | [r, g, b, a]
   *  }
   *  point: {
   *    size 圆点大小，像素数值值大小
   *    extra 其他参数（可选）
   *  },
   *  marker: {
   *    url 图标地址
   *    scale 图标缩放比例
   *    xoffset x偏移 （可选）
   *    yoffset y偏移 （可选）
   *    extra 其他参数（可选）
   *  },
   *  text: {
   *    value 文本内容
   *    color 填充颜色#ff0000 | [r, g, b, a]
   *    fontSize 字体大小
   *    outLineColor 边线颜色
   *    outLineWidth 边线宽度
   *    xoffset x偏移 （可选）
   *    yoffset y偏移 （可选）
   *    extra 其他参数（可选）
   *  }
   * }
   */
  getStyle(options) {
    // 创建线样式
    let outlineStyle = options.outline && this.getStrokeStyle(options.outline);
    // 创建面样式
    let fillStyle = options.fill && this.getFillStyle(options.fill.color);
    // 创建圆点
    let pointStyle = options.point && new this.modules.CircleStyle({
      radius: options.point.size / 2,
      fill: fillStyle,
      stroke: outlineStyle,
      ...(options.point.extra || {})
    });
    // 创建图标点
    let markerStyle = options.marker && new this.modules.Icon({
      src: options.marker.url,
      scale: options.marker.scale || 1,
      anchor: [options.marker.xoffset || 0.5, options.marker.yoffset || 1],
      ...(options.marker.extra || {})
    });
    //创建文本标注
    let textStyle = options.text && new this.modules.Text({
      font: options.text.font || undefined,
      text: String(options.text.value) || "",
      fill: new this.modules.Fill({ color: options.text.color || '#fff' }),
      stroke: options.text.outLineWidth && new this.modules.Stroke({ color: options.text.outLineColor || "#000", width: options.text.outLineWidth }),
      scale: options.text.fontSize ? options.text.fontSize / 12 : 1,
      offsetX: options.text.xoffset || 0,
      offsetY: options.text.yoffset || 0,
      ...(options.text.extra || {})
    });
    return new this.modules.Style({
      image: markerStyle || pointStyle, //优先以图标为主
      text: textStyle,
      stroke: outlineStyle,
      fill: fillStyle
    });
  }
  /**
   * 获取默认样式
   * @param {String} type 样式类型'point','marker','line','polygon'
   * @returns Object 样式对象
   */
  getDefaultStyle(type) {
    let style;
    if(type === "point") {
      style = new this.modules.Style({
        image: new this.modules.CircleStyle({
          radius: 6,
          fill: new this.modules.Fill({
            color: "#3D93FD"
          }),
          stroke: new this.modules.Stroke({
            color: '#fff',
            width: 1
          })
        }),
        zIndex: 3
      });
    }else if(type === "marker") {
      style = new this.modules.Style({
        image: new this.modules.Icon({
          anchor: [0.5, 0.9],
          src: "",
          scale: 0.52
        }),
        zIndex: 4
      });
    }else if(type === "line") {
      style = new this.modules.Style({
        stroke: new this.modules.Stroke({
          lineJoin: "round",
          color: '#4FC1DE',
          width: 3,
        }),
        zIndex: 2
      });
    }else if(type === "polygon") {
      style = new this.modules.Style({
        fill: new this.modules.Fill({
          color: [148, 219, 230, 0.28],
        }),
        stroke: new this.modules.Stroke({
          color: '#4FC1DE',
          width: 2,
        }),
        zIndex: 1
      });
    }
    return style;
  }
  /**
   * 间隔条纹样式线
   * @param {Object} options 
   *  @param {String} options.image 线样式贴图
   *  @param {String} options.scale 贴图缩放大小
   *  @param {String} options.lineColor 线颜色，默认 #089519
   *  @param {String} options.lineWidth 线宽，默认 6
   * @returns 
   */
  getStripeStyle(options = {}) {
    let lineStyle = new this.modules.Style({
      stroke: new this.modules.Stroke({
        color: options.lineColor || '#089519',
        width: options.lineWidth || 6
      })
    });
    let pointStyle = new this.modules.Style({
      image: new this.modules.Icon({
        scale: options.imageScale || 0.5,
        src: options.image || ''
      })
    });
    // 设置点样式坐标和角度
    const setPointStyle = (point, angle) => {
      let style = pointStyle.clone();
      style.setGeometry(new this.modules.Point(point));
      style.getImage().setRotation(angle);
      return style;
    }
    return (feature) => {
      let styles = [lineStyle];
      let geometry = feature.getGeometry();
      let length = geometry.getLength();
      let resolution = this.map.getView().getResolution() * 50;
      let count = Math.ceil(length / resolution);
      // 添加间断点
      for(let i = 1; i < count; i++) {
        let frag = i / count;
        let point = geometry.getCoordinateAt(frag);
        let point1 = geometry.getCoordinateAt(frag + 0.00000001);
        let angle = (Math.atan2(point1[0] - point[0], point1[1] - point[1])) - Math.PI / 2;
        styles.push(setPointStyle(point, angle));
      }
      return styles;
    }
  }
  /**
   * 创建要素数据
   * @param {Object} geometry 图形对象
   * @param {Object} style 样式
   * @param {Object} attributes 属性（可选）
   * @returns Object<Feature> 要素数据
   */
  createFeature(geometry, style, attributes) {
    let feature = new this.modules.Feature({ geometry });
    feature.setStyle(style);
    if(attributes) feature.setProperties(attributes);
    return feature;
  }
  /**
   * 设置要素样式
   * @param {Object} feature 图形要素
   * @param {Object} style 样式
   */
  setFeatureStyle(feature, style) {
    feature.setStyle(style);
  }
  /**
   * 设置要素图形信息
   * @param {Object} feature 图形要素
   * @param {Object} geometry 图形信息
   */
  setFeatureGeometry(feature, geometry) {
    feature.setGeometry(geometry);
  }
  /**
   * 设置要素属性信息
   * @param {Object} feature 图形要素
   * @param {Object} attributes 属性信息
   */
  setFeatureAttributes(feature, attributes) {
    feature.setProperties(attributes);
  }
  // 获取要素的图形对象
  getGeometryByFeature(feature) {
    if(Array.isArray(feature)) {
      return feature.map(item => item.getGeometry());
    }else {
      return feature.getGeometry();
    }
  }
  /**
   * 获取要素的图形对象
   * @param {Object|Array<Feature>} feature 单个/多个要素数据
   * @returns 图形对象数据
   */
  getAttributeByFeature(feature) {
    if(Array.isArray(feature)) {
      return feature.map(item => item.getProperties());
    }else {
      return feature.getProperties();
    }
  }
  /**
   * 添加高亮要素数据
   * @param {Object|Array<Feature>} feature 单个/多个要素数据
   */
  addHighLightFeature(feature) {
    if(Array.isArray(feature)) {
      this.highLightLayerSource.addFeatures(feature);
    }else {
      this.highLightLayerSource.addFeature(feature);
    }
  }
  // 清除高亮图层
  clearHighLightLayer() {
    this.highLightLayerSource.clear();
  }
  /**
   * 创建图形图层
   * @param {String} id 图层id 
   * @param {Boolean} isAdd 是否添加到地图
   * @returns 图层对象
   */
  createGraphicsLayer(id, isAdd = true) {
    let source = new this.modules.VectorSource({
      wrapX: false
    });
    let layer = new this.modules.VectorLayer({ id, source });
    if(isAdd) this.map.addLayer(layer);
    return layer;
  }
  /**
   * 创建热力图层
   * @param {
   *   id: String 图层id 
   *   features: Array<feature> 要素集
   *   blur: Number 热力模糊度
   *   radius: Number 热力半径 
   *   colors: Array<String> 颜色值
   *   weight: String|Function<feature> 权重值
   * } options
   * @param {Boolean} isAdd 是否添加到地图
   * @returns 图层对象
   */
  createHeatmapLayer(options, isAdd = true) {
    let source = new this.modules.VectorSource({
      wrapX: false,
      features: options.features
    });
    let layer = new this.modules.HeatmapLayer({ 
      id: options.id, 
      source,
      blur: options.blur,
      radius: options.radius,
      gradient: options.colors,
      weight: options.weight,
    });
    if(isAdd) this.map.addLayer(layer);
    return layer;
  }
  /**
   * 创建聚合图效果
   * @param {
   *   id: String 图层id 
   *   features: Array<feature> 要素集
   *   distance: Number 聚合距离，默认 35
   *   image: {
   *      url: String 不聚合时显示图标,
   *      scale: Number 缩放比例
   *      xoffset: Number x偏移
   *      yoffset: Number y偏移
   *   }
   *   style: Style | {
   *      innerRadius: Number 聚合内圆半径，默认 14
   *      innerColor: String 聚合内圆颜色，默认 'rgba(255, 165, 0, 0.7)'
   *      outerRadius: Number 聚合外圆半径，默认 20
   *      outerColor: String 聚合外圆颜色，默认 'rgba(255, 153, 102, 0.3)'
   *      textColor: String 文字颜色，默认 '#fff'
   *   }
   * } options 
   * @param {Boolean} isAdd 是否添加到地图
   * @returns 图层对象
   */
  createClusterLayer(options, isAdd = true) {
    let innerCircle = new this.modules.CircleStyle({
      radius: options.style?.innerRadius || 14,
      fill: new this.modules.Fill({
        color: options.style?.innerColor || 'rgba(255, 165, 0, 0.7)',
      }),
    });
    let outerCircle = new this.modules.CircleStyle({
      radius: options.style?.outerRadius || 20,
      fill: new this.modules.Fill({
        color: options.style?.outerColor || 'rgba(255, 153, 102, 0.3)',
      }),
    });
    let layer = new this.modules.VectorLayer({
      id: options.id,
      source: new this.modules.Cluster({
        distance: options.distance || 35,
        source: new this.modules.VectorSource({
          wrapX: false,
          features: options.features
        }),
      }),
      style: options.style instanceof this.modules.Style ? options.style : (feature => {
        let size = feature.get('features').length;
        if (size > 1) {
          return [
            new this.modules.Style({
              image: outerCircle,
            }),
            new this.modules.Style({
              image: innerCircle,
              text: new this.modules.Text({
                text: size.toString(),
                fill: new this.modules.Fill({
                  color: options.style?.textColor || '#fff',
                })
              }),
            }),
          ];
        } else {
          let originalFeature = feature.get('features')[0];
          let markerStyle = this.getMarkerStyle(options.image);
          markerStyle.geometry = originalFeature.getGeometry()
          return markerStyle;
        }
      }),
    });
    if(isAdd) this.map.addLayer(layer);
    return layer;
  }
  /**
   * 删除图层
   * @param {Object|String} layer|layerId 图形图层对象或id
   */
  removeLayer(layer) {
    let item = typeof(layer) === 'string' ? this.getLayerById(layer) : layer;
    this.map.removeLayer(item);
  }
  /**
   * 获取图层
   * @param {String} id 图层id 
   * @returns Object 图层对象
   */
  getLayerById(id) {
    return this.map.getLayers().getArray().find(item => id === item.getProperties().id);
  }
  /**
   * 添加要素到图层
   * @param {Object|String} layer|layerId 图形图层对象或id
   * @param {Object|Array<Feature>} feature 单个/多个要素数据
   */
  addFeatureToLayer(layer, feature) {
    if(Array.isArray(feature)) {
      typeof(layer) === 'string' ? this.getLayerById(layer).getSource().addFeatures(feature) : layer.getSource().addFeatures(feature);
    }else {
      typeof(layer) === 'string' ? this.getLayerById(layer).getSource().addFeature(feature) : layer.getSource().addFeature(feature);
    }
  }
  /**
   * 根据属性字段获取feature
   * @param {Object|String} layer|layerId 图形图层对象或id
   * @param {String} field 属性字段
   * @param {String} fieldValue 字段值
   */
  getFeatureFromLayer(layer, field, fieldValue) {
    let source = typeof(layer) === 'string' ? this.getLayerById(layer).getSource() : layer.getSource();
    let feature;
    source.forEachFeature(item => {
      if(item.getProperties() && item.getProperties()[field] === fieldValue) {
        feature = item;
      }
    });
    return feature;
  }
  /**
   * 根据属性字段删除feature
   * @param {Object|String} layer|layerId 图形图层对象或id
   * @param {String} field 属性字段
   * @param {String} fieldValue 字段值
   */
  removeFeatureFromLayer(layer, field, fieldValue) {
    let source = typeof(layer) === 'string' ? this.getLayerById(layer).getSource() : layer.getSource();
    source.forEachFeature(item => {
      if(item.getProperties() && item.getProperties()[field] === fieldValue) {
        source.removeFeature(item);
      }
    });
  }
  /**
   * 清除图形图层
   * @param {Object|String} layer|layerId 图形图层对象或id
   */
  clearGraphicsLayer(layer) {
    typeof(layer) === 'string' ? this.getLayerById(layer).getSource().clear() : layer.getSource().clear();
  }
  // 监听地图级别变化
  viewScaleListener(callback) {
    this.viewScaleEvent = this.map.getView().on("change:resolution", (e) => {
      if(callback) callback(e);
    });
    return this.viewScaleEvent;
  }
  // 监听地图范围变化
  viewExtentListener(callback) {
    this.viewExtentEvent = this.map.getView().on("change:center", () => {
      let centerCoords = this.map.getView().getCenter();
      let centerPoint = new this.modules.Point(centerCoords);
      let centerScreen = this.map.getPixelFromCoordinate(centerCoords);
      callback && callback({
        centerCoords,
        centerScreen: {
          x: centerScreen[0],
          y: centerScreen[1]
        },
        centerPoint
      });
    });
    this.viewSizeEvent = this.map.on("change:size", () => {
      let coordinate = this.map.getView().getCenter();
      let mapPoint = this.createPoint(coordinate[0], coordinate[1]);
      let screenPoint = this.map.getPixelFromCoordinate(coordinate);
      callback && callback({
        coordinate,
        screenPoint: {
          x: screenPoint[0],
          y: screenPoint[1]
        },
        mapPoint
      });
    });
    return [this.viewExtentEvent, this.viewSizeEvent];
  }
  // 监听鼠标移动
  pointerMoveListener(callback) {
    this.pointerMoveEvent = this.map.on("pointermove", evt => {
      callback && callback({
        coordinate: evt.coordinate,
        screenPoint: {
          x: evt.pixel[0],
          y: evt.pixel[1]
        },
        mapPoint: new this.modules.Point(evt.coordinate)
      });
    });
    return this.pointerMoveEvent;
  }
  // 地图点击事件
  mapOnClick(callback, isAgain) {
    if(this.mapClickEvent && isAgain) this.modules.unByKey(this.mapClickEvent);
    this.mapClickEvent = this.map.on("click", evt => {
      callback && callback({
        coordinate: evt.coordinate,
        screenPoint: {
          x: evt.pixel[0],
          y: evt.pixel[1]
        },
        mapPoint: new this.modules.Point(evt.coordinate)
      });
      if(!isAgain) this.modules.unByKey(this.mapClickEvent);
    });
    return this.mapClickEvent;
  }
  // 选中要素数据
  featureOnSelect(callback, isAgain = true) {
    if(this.featureSelectEvent && isAgain) this.modules.unByKey(this.featureSelectEvent);
    this.featureSelectEvent = this.map.on("click", evt => {
      let features = this.map.getFeaturesAtPixel(evt.pixel);
      callback && callback(features);
      if(!isAgain) this.modules.unByKey(this.featureSelectEvent);
    });
    return this.featureSelectEvent;
  }
  /**
   * 移除地图事件
   * @param {Object||Array<Object>} event 单个或多个事件对象
   */
  removeMapEvent(event) {
    if(Array.isArray(event)) {
      event.forEach(item => {
        // 地图范围变化事件为数组，event可能是二维数组
        if(Array.isArray(item)) {
          item.forEach(subItem => {
            if(subItem) this.modules.unByKey(subItem);
          });
        }
        if(item) this.modules.unByKey(item);
      });
    }else {
      if(event) this.modules.unByKey(event);
    }
  }
  /**
   * 显示弹窗
   * @param options {
   *  {String|HTMLElement} content 弹窗内容
   *  {Array} position 弹窗显示位置 [x, y]
   *  {Boolean} isCustom 是否自定义内容
   *  {Array} offset 偏移量 [x偏移，y偏移]
   *  {Function} callback 弹窗关闭后执行回调
   * }
   */
   showPopup(options) {
    let element = document.createElement("div");
    // 自定义弹窗内容
    if(options.isCustom) {
      if(typeof options.content === "string") {
        element.innerHTML = options.content;
      }else {
        element.appendChild(options.content);
      }
      this.overlay.setElement(element);
      this.overlay.setPosition(options.position);
    }else {
      // 默认弹窗样式
      element.innerHTML = `<div id="popup" class="ol-popup">
        <span id="popup-closer" class="ol-popup-closer"></span>
        <div class="popup-content"></div>
      </div>`;
      this.overlay.setElement(element);
      this.overlay.setPosition(options.position);
      let outContent = document.querySelector(".popup-content");
      if(typeof options.content === "string") {
        outContent.innerHTML = options.content;
      }else {
        outContent.appendChild(options.content);
      }
      document.getElementById("popup-closer").onclick = () => {
        this.overlay.setPosition(undefined);
        if(options.callback) options.callback();
      }
    }
    // 偏移量
    options.offset ? this.overlay.setOffset(options.offset) :  this.overlay.setOffset([0, 0]);
  }
  // 关闭弹窗
  closePopup() {
    this.overlay.setPosition(undefined);
  }
  // 获取长度（用于线）
  getLength(geometry) {
    return this.modules.getLength(geometry, {
      projection: this.viewProjection
    });
  }
  // 获取面积（用于面）
  getArea(geometry) {
    return this.modules.getArea(geometry, {
      projection: this.viewProjection
    });
  }
  /**
   * 获取图形之间的距离
   * @param {Object<Geometry>} geometry1 图形
   * @param {Object<Geometry>} geometry2 图形
   * @returns {Boolean} 距离
   */
  getGeometryDistance(geometry1, geometry2) {
    return this.jstsParser.read(geometry1).distance(this.jstsParser.read(geometry2));
  }
  /**
   * 合并图形
   * @param {Array<Geometry>} geometries 图形集合
   * @returns {Object<Geometry>} 合并后的图形
   */
  getUnionGeometry(geometries) {
    return geometries.reduce((pre, cur) => this.jstsParser.write(this.jstsParser.read(pre).union(this.jstsParser.read(cur))));
  }
  /**
   * 相交图形
   * @param {Object<Geometry>} geometry1 图形
   * @param {Object<Geometry>} geometry2 图形
   * @returns {Object<Geometry>} 相交图形
   */
  getIntersectGeometry(geometry1, geometry2) {
    return this.jstsParser.write(this.jstsParser.read(geometry1).intersection(this.jstsParser.read(geometry2)));
  }
  /**
   * 判断相交
   * @param {Object<Geometry>} geometry1 图形
   * @param {Object<Geometry>} geometry2 图形
   * @returns {Boolean} 是否相交
   */
  isIntersect(geometry1, geometry2) {
    return this.jstsParser.read(geometry1).intersects(this.jstsParser.read(geometry2));
  }
  /**
   * 判断包含
   * @param {Object<Geometry>} outGeometry 图形（外）
   * @param {Object<Geometry>} inGeometry 图形（内）
   * @returns {Boolean} 是否包含
   */
  isContains(outGeometry, inGeometry) {
    return this.jstsParser.read(outGeometry).contains(this.jstsParser.read(inGeometry));
  }
  // 地图销毁释放地图资源
  destroy() {
    this.map.setTarget(undefined);
    this.map = null;
  }
}

export default MapClass;